﻿using System;
using System.Collections.Generic;
using KC.Common;
using KC.Framework.Tenant;
using KC.Service.Core.Attribute;
using KC.Service.Core.Constants;
using KC.DTO.Admin;
using KC.DTO.Core;
using System.Reflection;
using System.Threading.Tasks;
using System.Net.Http;

namespace KC.Service.Core.WebApiService.Business
{
    public interface ITenantUserApiService
    {
        #region Tenant Api
        Task<ServiceResult<bool>> ExistTenantName(string tenantName);

        //[WebCachingCallHandler("KC.Service.Admin.ITenantUserService-GetTenantByName", TimeOutConstants.DefaultCacheTimeOut, Order = 0)]
        //[CachingCallHandler("KC.Service.Admin.ITenantUserService-GetTenantByName", TimeOutConstants.DefaultCacheTimeOut, 0, Order = 0)]
        Task<Tenant> GetTenantByName(string tenantName);
        //[WebCachingCallHandler("KC.Service.Admin.ITenantUserService-GetTenantByNameOrNickName", TimeOutConstants.DefaultCacheTimeOut, Order = 0)]
        //[CachingCallHandler("KC.Service.Admin.ITenantUserService-GetTenantByNameOrNickName", TimeOutConstants.DefaultCacheTimeOut, 0, Order = 0)]
        Task<Tenant> GetTenantByNameOrNickName(string tenantName);
        //[WebCachingCallHandler("KC.Service.Admin.ITenantUserService-GetTenantEndWithDomainName", TimeOutConstants.DefaultCacheTimeOut, Order = 0)]
        //[CachingCallHandler("KC.Service.Admin.ITenantUserService-GetTenantEndWithDomainName", TimeOutConstants.DefaultCacheTimeOut, 0, Order = 0)]
        Task<Tenant> GetTenantEndWithDomainName(string domainName);
        Task<Tenant> GetTenantByAppIdWithName(Guid appId, string tenantName);
        Task<TenantUserDTO> GetTenantUserByName(string tenantName);
        Task<TenantUserDTO> GetTenantUserByNameUnCache(string tenantName);//不缓存,要实时的数据

        //[WebCachingCallHandler(TimeOutConstants.DefaultCacheTimeOut, Order = 0)]
        Task<List<Tenant>> GetAllOpenAppTenants(Guid appId);
        Task<List<Tenant>> GetOpenAppTenantsByNames(Guid appId, List<string> tenantNames);
        Task<List<Tenant>> GetTenantByTenantNames(List<string> tenantNames);

        Task<PaginatedBaseDTO<TenantSimpleDTO>> GetTenantUsersByOpenAppId(int pageIndex, int pageSize, Guid applicationId,
            string tenantDisplayName, string exceptTenant);

        string GetTenantDisplayNameByName(string name);
        #endregion

    }

    /// <summary>
    /// 注意：TenantUserApiService，默认使用的Dba的身份去访问接口，故基类中的Tenant永远为Dba
    /// </summary>
    public class TenantUserApiService : IdSrvOAuth2ClientRequestBase, ITenantUserApiService
    {
        private const string ServiceName = "KC.Service.Core.WebApiService.TenantUserApiService";

        public TenantUserApiService(
            IHttpClientFactory httpClient,
            Microsoft.Extensions.Logging.ILogger<TenantUserApiService> logger)
            : base(TenantConstant.DbaTenantApiAccessInfo, httpClient, logger)
        {
        }

        public async Task<ServiceResult<bool>> ExistTenantName(string tenantName)
        {
            ServiceResult<bool> result = null;
            await WebSendGetAsync<ServiceResult<bool>>(
                ServiceName + ".ExistTenantName",
                AdminApiServiceUrl + "TenantApi/ExistTenantName?tenantName=" + tenantName,
                ApplicationConstant.AdminScope, 
                callback =>
                {
                    result = callback;
                },
                (httpStatusCode, errorMessage) =>
                {
                    result = new ServiceResult<bool>(ServiceResultType.Error, httpStatusCode, errorMessage);
                },
                false);

            return result;
        }

        #region 获取Tenant数据，清理租户的缓存写在了SSO项目：KC.Service.Admin.TenantUserService.SaveTenantUser
        public async Task<Tenant> GetTenantByName(string tenantName)
        {
            //使用IIS缓存
            //var key = GetCacheKeyUtil.CacheKeyGenerator(MethodBase.GetCurrentMethod(), new object[] { tenantName }, string.Empty, 0);
            //var tenant = KC.Service.Core.Util.LocalWebCacheUtil.GetCache<Tenant>(key);
            //使用Redis缓存
            var key = GetCacheKeyUtil.CacheKeyGenerator(MethodBase.GetCurrentMethod(), new object[] { tenantName }, string.Empty, 0);
            var tenant = CacheUtil.GetCache<Tenant>(key);

            if (tenant != null) return tenant;

            ServiceResult<Tenant> result = null;
            await WebSendGetAsync<ServiceResult<Tenant>>(
                ServiceName + ".GetTenantUserByName",
                AdminApiServiceUrl + "TenantApi/GetTenantByTenantName?tenantName=" + tenantName,
                ApplicationConstant.AdminScope, 
                callback =>
                {
                    result = callback;
                },
                (httpStatusCode, errorMessage) =>
                {
                    result = new ServiceResult<Tenant>(ServiceResultType.Error, httpStatusCode, errorMessage);
                },
                true);

            if (result.success && result.Result != null)
            {
                //使用IIS缓存
                //KC.Service.Core.Util.LocalWebCacheUtil.SetCache(key, result.Result, TimeSpan.FromMinutes(TimeOutConstants.DefaultCacheTimeOut));
                //使用Redis缓存
                CacheUtil.SetCache(key, result.Result, TimeSpan.FromMinutes(TimeOutConstants.DefaultCacheTimeOut));
                return result.Result;
            }
            return null;
        }
        public async Task<Tenant> GetTenantByNameOrNickName(string tenantName)
        {
            //使用IIS缓存
            //var key = GetCacheKeyUtil.CacheKeyGenerator(MethodBase.GetCurrentMethod(), new object[] { tenantName }, string.Empty, 0);
            //var tenant = KC.Service.Core.Util.LocalWebCacheUtil.GetCache<Tenant>(key);
            //使用Redis缓存
            var key = GetCacheKeyUtil.CacheKeyGenerator(MethodBase.GetCurrentMethod(), new object[] { tenantName }, string.Empty, 0);
            var tenant = CacheUtil.GetCache<Tenant>(key);

            if (tenant != null) return tenant;

            ServiceResult<Tenant> result = null;
            await WebSendGetAsync<ServiceResult<Tenant>>(
                ServiceName + ".GetTenantByNameOrNickName",
                AdminApiServiceUrl + "TenantApi/GetTenantByNameOrNickName?tenantName=" + tenantName,
                ApplicationConstant.AdminScope, 
                callback =>
                {
                    result = callback;
                },
                (httpStatusCode, errorMessage) =>
                {
                    result = new ServiceResult<Tenant>(ServiceResultType.Error, httpStatusCode, errorMessage);
                },
                true);

            if (result.success && result.Result != null)
            {
                //使用IIS缓存
                //KC.Service.Core.Util.LocalWebCacheUtil.SetCache(key, result.Result, TimeSpan.FromMinutes(TimeOutConstants.DefaultCacheTimeOut));
                //使用Redis缓存
                CacheUtil.SetCache(key, result.Result, TimeSpan.FromMinutes(TimeOutConstants.DefaultCacheTimeOut));
                return result.Result;
            }
            return null;
        }
        public async Task<Tenant> GetTenantEndWithDomainName(string domainName)
        {
            //使用IIS缓存
            //var key = GetCacheKeyUtil.CacheKeyGenerator(MethodBase.GetCurrentMethod(), new object[] { domainName }, string.Empty, 0);
            //var tenant = KC.Service.Core.Util.LocalWebCacheUtil.GetCache<Tenant>(key);
            //使用Redis缓存
            var key = GetCacheKeyUtil.CacheKeyGenerator(MethodBase.GetCurrentMethod(), new object[] { domainName }, string.Empty, 0);
            var tenant = CacheUtil.GetCache<Tenant>(key);

            if (tenant != null) return tenant;

            ServiceResult<Tenant> result = null;
            await WebSendGetAsync<ServiceResult<Tenant>>(
                ServiceName + ".GetTenantEndWithDomainName",
                AdminApiServiceUrl + "TenantApi/GetTenantEndWithDomainName?domainName=" + domainName,
                ApplicationConstant.AdminScope, 
                callback =>
                {
                    result = callback;
                },
                (httpStatusCode, errorMessage) =>
                {
                    result = new ServiceResult<Tenant>(ServiceResultType.Error, httpStatusCode, errorMessage);
                },
                true);
            if (result.success && result.Result != null)
            {
                //使用IIS缓存
                //KC.Service.Core.Util.LocalWebCacheUtil.SetCache(key, result.Result, TimeSpan.FromMinutes(TimeOutConstants.DefaultCacheTimeOut));
                //使用Redis缓存
                CacheUtil.SetCache(key, result.Result, TimeSpan.FromMinutes(TimeOutConstants.DefaultCacheTimeOut));
                return result.Result;
            }

            return null;
        }
        public async Task<TenantUserDTO> GetTenantUserByName(string tenantName)
        {
            ServiceResult<TenantUserDTO> result = null;
            await WebSendGetAsync<ServiceResult<TenantUserDTO>>(
                ServiceName + ".GetTenantUserByName",
                AdminApiServiceUrl + "TenantApi/GetTenantUserByName?tenantName=" + tenantName,
                ApplicationConstant.AdminScope, 
                callback =>
                {
                    result = callback;
                },
                (httpStatusCode, errorMessage) =>
                {
                    result = new ServiceResult<TenantUserDTO>(ServiceResultType.Error, httpStatusCode, errorMessage);
                },
                true);

            if (result.success && result.Result != null)
            {
                return result.Result;
            }

            return null;
        }
        public async Task<TenantUserDTO> GetTenantUserByNameUnCache(string tenantName)
        {
            ServiceResult<TenantUserDTO> result = null;
            await WebSendGetAsync<ServiceResult<TenantUserDTO>>(
                ServiceName + ".GetTenantUserByName",
                AdminApiServiceUrl + "TenantApi/GetTenantUserByNameUnCache?tenantName=" + tenantName,
                ApplicationConstant.AdminScope,
                callback =>
                {
                    result = callback;
                },
                (httpStatusCode, errorMessage) =>
                {
                    result = new ServiceResult<TenantUserDTO>(ServiceResultType.Error, httpStatusCode, errorMessage);
                },
                true);

            if (result.success && result.Result != null)
                return result.Result;

            return null;
        }
        public async Task<Tenant> GetTenantByAppIdWithName(Guid appId, string tenantName)
        {
            ServiceResult<Tenant> result = null;
            await WebSendGetAsync<ServiceResult<Tenant>>(
                ServiceName + ".GetMarketAppTenant",
                AdminApiServiceUrl + "TenantApi/GetTenantByAppIdWithName?tenantName=" + tenantName + "&appId=" + appId,
                ApplicationConstant.AdminScope,
                callback =>
                {
                    result = callback;
                },
                (httpStatusCode, errorMessage) =>
                {
                    result = new ServiceResult<Tenant>(ServiceResultType.Error, httpStatusCode, errorMessage);
                },
                true);

            if (result.success && result.Result != null)
                return result.Result;

            return null;
        }

        public async Task<List<Tenant>> GetAllOpenAppTenants(Guid appId)
        {
            var key = GetCacheKeyUtil.CacheKeyGenerator(MethodBase.GetCurrentMethod(), new object[] { appId }, string.Empty, -1);
            var tenant = CacheUtil.GetCache<List<Tenant>>(key);
            if (tenant != null) return tenant;

            ServiceResult<List<Tenant>> result = null;
            await WebSendGetAsync<ServiceResult<List<Tenant>>>(
                ServiceName + ".GetAllOpenAppTenants",
                AdminApiServiceUrl + "TenantApi/GetAllOpenAppTenants?appId=" + appId,
                ApplicationConstant.AdminScope, 
                callback =>
                {
                    result = callback;
                },
                (httpStatusCode, errorMessage) =>
                {
                    result = new ServiceResult<List<Tenant>>(ServiceResultType.Error, httpStatusCode, errorMessage);
                },
                true);

            if (result.success && result.Result != null)
            {
                CacheUtil.SetCache(key, result.Result, TimeSpan.FromMinutes(TimeOutConstants.DefaultCacheTimeOut));
                return result.Result;
            }

            return null;
        }
        public async Task<List<Tenant>> GetTenantByTenantNames(List<string> tenantNames)
        {
            var jsonData = SerializeHelper.ToJson(tenantNames);
            ServiceResult<List<Tenant>> result = null;
            await WebSendPostAsync<ServiceResult<List<Tenant>>>(
                ServiceName + ".GetTenantByTenantNames",
                AdminApiServiceUrl + "TenantApi/GetTenantByTenantNames",
                ApplicationConstant.AdminScope,
                jsonData,
                callback =>
                {
                    result = callback;
                },
                (httpStatusCode, errorMessage) =>
                {
                    result = new ServiceResult<List<Tenant>>(ServiceResultType.Error, httpStatusCode, errorMessage);
                },
                true);

            if (result.success && result.Result != null)
            {
                return result.Result;
            }

            return null;
        }
        public async Task<List<Tenant>> GetOpenAppTenantsByNames(Guid appId, List<string> tenantNames)
        {
            var jsonData = SerializeHelper.ToJson(tenantNames);
            ServiceResult<List<Tenant>> result = null;
            await WebSendPostAsync<ServiceResult<List<Tenant>>>(
                ServiceName + ".GetOpenAppTenantsByNames",
                AdminApiServiceUrl + "TenantApi/GetOpenAppTenantsByNames?appId=" + appId,
                ApplicationConstant.AdminScope, 
                jsonData,
                callback =>
                {
                    result = callback;
                },
                (httpStatusCode, errorMessage) =>
                {
                    result = new ServiceResult<List<Tenant>>(ServiceResultType.Error, httpStatusCode, errorMessage);
                },
                true);

            if (result.success && result.Result != null)
                return result.Result;

            return null;
        }
        
        public async Task<PaginatedBaseDTO<TenantSimpleDTO>> GetTenantUsersByOpenAppId(int pageIndex, int pageSize, Guid applicationId,
            string tenantDisplayName, string exceptTenant)
        {
            ServiceResult<PaginatedBaseDTO<TenantSimpleDTO>> result = null;
            await WebSendGetAsync<ServiceResult<PaginatedBaseDTO<TenantSimpleDTO>>>(
                ServiceName + ".GetTenantUsersByOpenAppId",
                AdminApiServiceUrl + "TenantApi/GetTenantUsersByOpenAppId?pageIndex=" + pageIndex + "&pageSize=" +
                    pageSize + "&applicationId=" + applicationId + "&tenantDisplayName=" + tenantDisplayName +
                    "&exceptTenant=" + exceptTenant,
                ApplicationConstant.AdminScope,
                callback =>
                {
                    result = callback;
                },
                (httpStatusCode, errorMessage) =>
                {
                    result = new ServiceResult<PaginatedBaseDTO<TenantSimpleDTO>>(ServiceResultType.Error, httpStatusCode, errorMessage);
                },
                true);

            if (result.success && result.Result != null)
                return result.Result;

            return null;
        }
   
        public string GetTenantDisplayNameByName(string name)
        {
            ServiceResult<string> result = null;
            WebSendGet<ServiceResult<string>>(
                ServiceName + ".GetTenantDisplayNameByName",
                AdminApiServiceUrl + "TenantApi/GetTenantDisplayNameByName?name=" + name,
                ApplicationConstant.AdminScope,
                null,
                callback =>
                {
                    result = callback;
                },
                (httpStatusCode, errorMessage) =>
                {
                    result = new ServiceResult<string>(ServiceResultType.Error, httpStatusCode, errorMessage);
                });

            return result.Result;
        }
        #endregion

    }
}
